package it.polimi.swKnights.SWIMv2.ejb.searchEngine;

import it.polimi.swKnights.SWIMv2.ejb.authentication.LoginHandlerLocal;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.RegisteredUser;
import it.polimi.swKnights.SWIMv2.ejb.personalData.PersonalDataManagerLocal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public abstract class Search
{
	@PersistenceContext(unitName = "swimv2-manager")
	protected EntityManager managerUC;

	@EJB
	protected LoginHandlerLocal loginManager;

	@EJB
	protected PersonalDataManagerLocal dataManager;

	protected final List<Map<String, String>> createListOfMap(
			List<UserQueryResult> listQR)
	{

		List<Map<String, String>> listOfMapOfResults = new LinkedList<Map<String, String>>();

		for (UserQueryResult uqr : listQR)
		{
			Map<String, String> userData = this.dataManager.getUserDataMap(
					uqr.getUser(), uqr.getResultCategory(), uqr.getAbility());
			listOfMapOfResults.add(userData);
		}

		return listOfMapOfResults;
	}

	/**
	 * From advanced search we reuse part of the method to look for users with
	 * some parameters
	 */

	protected final List<UserQueryResult> findUserWithCertainAbilityAndOther(
			String ability, String name, String surname, String email,
			String city, String queryForUsers, ResultCategory resultCategory)
	{
		
		name = emptyToWild(name);
		surname = emptyToWild(surname);
		email = emptyToWild(email);
		city = emptyToWild(city);

		// query for ability

		String queryText = queryForUsers;
		/*
		 * for instance: +
		 * "SELECT ru FROM RegisteredUser AS ru WHERE :ability= " +
		 * "ANY(SELECT a FROM RegisteredUser u, IN (u.abilities) a WHERE u=ru) "
		 * + "AND ru.name LIKE :name" + "  AND ru.surname LIKE :surname " +
		 * "AND ru.email LIKE :email";
		 */

		Query q;
		q = managerUC.createQuery(queryText);

		q.setParameter("ability", ability);
		q.setParameter("name", name);
		q.setParameter("surname", surname);
		q.setParameter("email", email);
		q.setParameter("ability", ability);
		q.setParameter("city", city);

		List<?> queryListSec = q.getResultList();

		List<UserQueryResult> lstRightAbility = new ArrayList<UserQueryResult>();

		for (Object item : queryListSec)
		{
			RegisteredUser regUser = (RegisteredUser) item;
			UserQueryResult uq = new UserQueryResult(regUser, resultCategory,
					100, ability);
			lstRightAbility.add(uq);
		}

		return lstRightAbility;
	}

	protected final List<UserQueryResult> getUserWithNameSurnameMail(
			String name, String surname, String email, String city,
			String queryUsers, ResultCategory resultCategory)
	{

		// search reg. user with spec. ability except then ability
		List<UserQueryResult> lstRightNameSurnEmail = new ArrayList<UserQueryResult>();

		name = emptyToWild(name);
		surname = emptyToWild(surname);
		email = emptyToWild(email);
		city = emptyToWild(city);

		
		String queryText = queryUsers;
		Query query = managerUC.createQuery(queryText);
		query.setParameter("name", name);
		query.setParameter("surname", surname);
		query.setParameter("email", email);
		query.setParameter("city", city);

		List<?> queryList = query.getResultList();

		for (Object item : queryList)
		{
			RegisteredUser regUser = (RegisteredUser) item;
			UserQueryResult uq = new UserQueryResult(regUser, resultCategory,
					100, "");

			lstRightNameSurnEmail.add(uq);
		}

		return lstRightNameSurnEmail;
	}

	protected final ResultCategory getResultCategory(String queryAttribute)
	{
		ResultCategory resultCategory = null;
		if (queryAttribute.equals("userName"))
		{
			resultCategory = ResultCategory.username;
		}
		else if (queryAttribute.equals("name"))
		{
			resultCategory = ResultCategory.name;
		}
		else if (queryAttribute.equals("surname"))
		{
			resultCategory = ResultCategory.surname;
		}
		return resultCategory;
	}

	/**
	 * tool to remove duplicated item from list or query result, we cannot user
	 * java first-class methods because object are not equals because they have
	 * different rankings
	 * 
	 * @param listQR
	 */

	protected final void removeSameUserDifferentRanking(
			List<UserQueryResult> listQR)
	{

		if (listQR.size() <= 1)
			return;

		Comparator<UserQueryResult> c = new Comparator<UserQueryResult>()
		{

			@Override
			public int compare(UserQueryResult uq1, UserQueryResult uq2)
			{

				if (uq1.refersToSameUser(uq2)) // same userName
				{
					return -1 * uq1.compareTo(uq2); // if same user compare ranking
				}
				else
				// different userName
				{
					return uq1.getUsername().compareTo(uq2.getUsername());
				}
			}
		};
		Collections.sort(listQR, c);

		UserQueryResult u1, u2;
		int i;

		/*
		 * u1 -> A u1 -> A u1-> A A U2 -> A -------------- u2-> A --------- A A
		 * B B B B C C C C C C C C
		 */

		// __________________________________________________________________

		/*
		 * u1 -> A A A u2 _> B u1-> B B C u2-> C u1-> C C C u2-> C
		 */

		for (i = 0; i < listQR.size(); i++)
		{
			u1 = listQR.get(i);
			if (!(i + 1 >= listQR.size()))
			{
				u2 = listQR.get(i + 1);

				if (u1.refersToSameUser(u2))
				{
					listQR.remove(u2);
					i--; // the loop is to iterate another time with the same
							// copy candidate
					//
				}

			}
		}

	}

	/**
	 * remove words of 1 or 2 letters, such as: as, an, of, by
	 * 
	 * @param query
	 * @return
	 */
	protected final String removeUselessWords(String query)
	{
		String words[] = query.split(" ");
		String newQuery = "";
		for (String word : words)
		{
			if (word.length() > 2)
			{
				newQuery = newQuery + (newQuery.length() == 0 ? "" : " ")
						+ word;

			}
		}
		return newQuery;
	}

	protected final void checkValidParameterQuery(String queryAttribute)
	{
		if (queryAttribute.equals("name") || queryAttribute.equals("surname")
				|| queryAttribute.equals("userName"))
		{
		}
		else
		{
			throw new IllegalArgumentException(
					" eheh maledetto ema, volevi fregarci!! ;) ;) ");
		}

	}

	/**
	 * simple tool to "cast" null to %, also "" to % useful for advanced search
	 * cause we exploit LIKE operator
	 * 
	 * @param parameter
	 * @return
	 */
	protected final String emptyToWild(String parameter)
	{
		if (parameter == null || parameter.equals(""))
		{
			return "%";
		}
		else
		{
			return parameter;
		}
	}

}
